package model

import (
	"errors"
	"fmt"
	"gitee.com/damengde/treebark/util"
	"reflect"
	"strings"
)

type MatchType uint

const (
	TagName       = "bark"
	TagAttrName   = "name"
	TagAttrColumn = "column"
	Id            = "id"
	ParentId      = "parentId"
	Level         = "level"
	TreeId        = "treeId"
	Left          = "lft"
	Right         = "rgt"

	MatchTypeTag  = MatchType(1)
	MatchTypeName = MatchType(2)
)

// FieldAttr 字段属性
type FieldAttr struct {
	Name   string       //字段名
	Index  []int        //索引
	Type   reflect.Kind //字段类型
	Column string       // sql字段
}

// NodeField 结节字段结构体
type NodeField struct {
	Id       FieldAttr
	ParentId FieldAttr
	Level    FieldAttr
	TreeId   FieldAttr
	Left     FieldAttr
	Right    FieldAttr
}

// New 解析model结构体的信息
func New(obj any) (node *NodeField, err error) {
	node = &NodeField{}
	if node.Id, err = getTreeFieldAttr(obj, Id); err != nil {
		return
	}
	if node.ParentId, err = getTreeFieldAttr(obj, ParentId); err != nil {
		return
	}
	if node.Level, err = getTreeFieldAttr(obj, Level); err != nil {
		return
	}
	if node.TreeId, err = getTreeFieldAttr(obj, TreeId); err != nil {
		return
	}
	if node.Left, err = getTreeFieldAttr(obj, Left); err != nil {
		return
	}
	if node.Right, err = getTreeFieldAttr(obj, Right); err != nil {
		return
	}
	return node, nil
}

func (t *NodeField) GetID(node any) any {
	return util.GetFieldValue(node, t.Id.Index)
}

func (t *NodeField) GetParentId(node any) any {
	return util.GetFieldValue(node, t.ParentId.Index)
}

func (t *NodeField) GetLeft(node any) int64 {
	return util.GetFieldIntValue(node, t.Left.Index)
}

func (t *NodeField) GetRight(node any) int64 {
	return util.GetFieldIntValue(node, t.Right.Index)
}

func (t *NodeField) GetLevel(node any) int64 {
	return util.GetFieldIntValue(node, t.Level.Index)
}

func (t *NodeField) GetTreeId(node any) any {
	return util.GetFieldValue(node, t.TreeId.Index)
}

func (t *NodeField) SetID(node, value any) {
	util.SetFieldValue(node, value, t.Id.Index)
}

func (t *NodeField) SetParentId(node, value any) {
	util.SetFieldValue(node, value, t.ParentId.Index)
}

func (t *NodeField) SetTreeId(node, value any) {
	util.SetFieldValue(node, value, t.TreeId.Index)
}

func (t *NodeField) SetLeft(node, value any) {
	util.SetFieldValue(node, value, t.Left.Index)
}

func (t *NodeField) SetRight(node, value any) {
	util.SetFieldValue(node, value, t.Right.Index)
}

func (t *NodeField) SetLevel(node, value any) {
	util.SetFieldValue(node, value, t.Level.Index)
}

// getTreeFieldAttr 获取字段属性
func getTreeFieldAttr(obj any, tagName string) (attr FieldAttr, err error) {
	// 根据标签名查找
	if util.ReflectLookupField(obj, fieldAttrMatch(tagName, &attr, MatchTypeTag)) {
		return
	}

	// 根据字段名开始查找
	if util.ReflectLookupField(obj, fieldAttrMatch(tagName, &attr, MatchTypeName)) {
		return
	}

	//字段名也没找到
	return attr, errors.New(fmt.Sprintf("critical field tag %s:%s and field name %s not found", TagName, tagName, tagName))
}

// fieldAttrMatch 字段属性匹配
func fieldAttrMatch(tagName string, attr *FieldAttr, matchType MatchType) func(name string, getTag func(key string) string, index []int) bool {
	return func(name string, getTag func(key string) string, index []int) bool {
		tagAttrMap := util.ParseTag(getTag(TagName))
		lowerTagName := strings.ToLower(tagName)
		// 匹配标签和字段名
		if (matchType == MatchTypeTag && (len(tagAttrMap) == 0 ||
			strings.ToLower(tagAttrMap[TagAttrName]) != lowerTagName &&
				strings.ToLower(tagAttrMap[tagName]) != lowerTagName)) ||
			(matchType == MatchTypeName && strings.ToLower(name) != lowerTagName) {
			return false
		}

		col := tagAttrMap[TagAttrColumn]
		if col == "" {
			col = util.CamelToSnakeCase(name)
		}
		attr.Name, attr.Index, attr.Column = name, index, col
		return true
	}
}
